using System;
using System.Collections;
using System.Collections.Generic;
using NUnit.Framework;
using ValidationFramework.Reflection;

namespace ValidationFramework.Tests
{
    public class LengthCollectionRuleTest
    {
        public class MyCollection : ICollection<int>
        {
            public void CopyTo(Array array, int index)
            {
                throw new NotImplementedException();
            }

            public void Add(int item)
            {
                throw new NotImplementedException();
            }

            public void Clear()
            {
                throw new NotImplementedException();
            }

            public bool Contains(int item)
            {
                throw new NotImplementedException();
            }

            public void CopyTo(int[] array, int arrayIndex)
            {
                throw new NotImplementedException();
            }

            public bool Remove(int item)
            {
                throw new NotImplementedException();
            }

            public int Count
            {
                get
                {
                    return 5;
                }
            }

            public bool IsReadOnly
            {
                get
                {
                    throw new NotImplementedException();
                }
            }

            IEnumerator<int> IEnumerable<int>.GetEnumerator()
            {
                throw new NotImplementedException();
            }

            public IEnumerator GetEnumerator()
            {
                throw new NotImplementedException();
            }
        }

        const int expectedMinimum = 2;
        const int expectedMaximum = 4;
        const string expectedErrorMessage = "expectedErrorMessage";
        const string expectedRuleSet = "EXPECTEDRULESET";

        [TestFixture]
        public class Contruction
        {
            [Test]
            public void Simple1()
            {
                var rule = new LengthCollectionRule(expectedErrorMessage, false, expectedMinimum, expectedMaximum, true, null);
                Assert.AreEqual(expectedMinimum, rule.Minimum);
                Assert.AreEqual(expectedMaximum, rule.Maximum);
                Assert.AreEqual(expectedErrorMessage, rule.ErrorMessage);
                Assert.IsTrue(rule.ExcludeDuplicatesFromCount);
                Assert.IsFalse(rule.UseErrorMessageProvider);
            }


            [Test]
            public void Simple2()
            {

                var rule = new LengthCollectionRule(expectedErrorMessage, expectedMinimum, expectedMaximum);
                Assert.AreEqual(expectedMinimum, rule.Minimum);
                Assert.AreEqual(expectedMaximum, rule.Maximum);
                Assert.AreEqual(expectedErrorMessage, rule.ErrorMessage);
                Assert.IsFalse(rule.ExcludeDuplicatesFromCount);
                Assert.IsFalse(rule.UseErrorMessageProvider);
            }


            [Test]
            public void Simple3()
            {

                var rule = new LengthCollectionRule(expectedMinimum, expectedMaximum);
                Assert.AreEqual(expectedMinimum, rule.Minimum);
                Assert.AreEqual(expectedMaximum, rule.Maximum);
                Assert.IsNull(rule.ErrorMessage);
                Assert.IsFalse(rule.ExcludeDuplicatesFromCount);
                Assert.IsFalse(rule.UseErrorMessageProvider);
            }
            [Test]
            public void MinimumEqualMaximum()
            {
                new LengthCollectionRule(null, false, 1, 1, true, null);
            }
            [Test]
            [ExpectedException(typeof(ArgumentException), ExpectedMessage = "Minimum must be less than or equal to Maximum.\r\nParameter name: minimum")]
            public void ExceptionMinimumGreaterThanMaximum()
            {
                new LengthCollectionRule(null, false, 2, 1, true, null);
            }
        }
            [TestFixture]
        public class RuleInterpretation
            {
                [Test]
                public void SameValues()
                {
                    var rule = new LengthCollectionRule(null, expectedMaximum, expectedMaximum);
                    Assert.IsNotNull(rule.RuleInterpretation);
                }

                [Test]
                public void DifferentValues()
                {
                    var rule = new LengthCollectionRule(null, expectedMinimum, expectedMaximum);
                    Assert.IsNotNull(rule.RuleInterpretation);
                }

            }
        [TestFixture]
            public class IsEquivalent
        {
            [Test]
            public void Simple()
            {
                var rule1 = new LengthCollectionRule(null, false, 10, 15, true, null);
                var rule2 = new LengthCollectionRule(null, false, 10, 15, true, null);
                Assert.IsTrue(rule1.IsEquivalent(rule2));

                rule2 = new LengthCollectionRule(null, false, 10, 15, false, null);
                Assert.IsFalse(rule1.IsEquivalent(rule2));
            }
        }

        [TestFixture]
        public class GetComputedErrorMessage
        {
            [Test]
            public void SameValues()
            {
                var rule = new LengthCollectionRule(null, false, expectedMinimum, expectedMinimum, true, null);
                rule.SetDefaultErrorMessage(new MockInfoDescriptor(typeof(ICollection).TypeHandle, "foo"));
                Assert.IsFalse(string.IsNullOrEmpty(rule.ErrorMessage));
            }

            [Test]
            public void DifferentValues()
            {
                var rule = new LengthCollectionRule(null, false, expectedMinimum, expectedMaximum, true, null);
                rule.SetDefaultErrorMessage(new MockInfoDescriptor(typeof(ICollection).TypeHandle, "foo"));
                Assert.IsFalse(string.IsNullOrEmpty(rule.ErrorMessage));
            }
        }
        [TestFixture]
        public class Validate
        {

            [Test]
            public void ValidateGenericIncludeDuplicates()
            {

                var rule = new LengthCollectionRule(null, false, expectedMinimum, expectedMaximum, false, null);
                 rule.CheckType(new MockInfoDescriptor(typeof(IList).TypeHandle, "foo"));

                List<int> list = null;
                Assert.IsNull(rule.Validate(null, list, null, null));
                list = new List<int>();
                Assert.IsNotNull(rule.Validate(null, list, null, null));

                list.Add(1);
                Assert.IsNotNull(rule.Validate(null, list, null, null));

                list.Add(1);
                Assert.IsNull(rule.Validate(null, list, null, null));

                list.Add(1);
                Assert.IsNull(rule.Validate(null, list, null, null));

                list.Add(1);
                Assert.IsNull(rule.Validate(null, list, null, null));

                list.Add(1);
                Assert.IsNotNull(rule.Validate(null, list, null, null));
            }

			
#if (!SILVERLIGHT)
            [Test]
            public void ValidateGenericExcludeDuplicates()
            {
                var rule = new LengthCollectionRule(null, false, expectedMinimum, expectedMaximum, true, null);
                rule.CheckType(new MockInfoDescriptor(typeof (ArrayList).TypeHandle, "foo"));
                List<int> list = null;
                Assert.IsNull(rule.Validate(null, list, null, null));

                list = new List<int>();
                Assert.IsNotNull(rule.Validate(null, list, null, null));

                list.Add(1);
                Assert.IsNotNull(rule.Validate(null, list, null, null));

                list.Add(1);
                Assert.IsNotNull(rule.Validate(null, list, null, null));

                list.Add(1);
                Assert.IsNotNull(rule.Validate(null, list, null, null));

                list.Add(2);
                Assert.IsNull(rule.Validate(null, list, null, null));

                list.Add(3);
                Assert.IsNull(rule.Validate(null, list, null, null));

                list.Add(4);
                Assert.IsNull(rule.Validate(null, list, null, null));
            }
            [Test]
            public void ValidateNonGenericIncludeDuplicates()
            {
                var rule = new LengthCollectionRule(null, false, expectedMinimum, expectedMaximum, false, null);
                rule.CheckType(new MockInfoDescriptor(typeof (ArrayList).TypeHandle, "foo"));
                ArrayList list = null;
                Assert.IsNull(rule.Validate(null, list, null, null));
                list = new ArrayList();
                Assert.IsNotNull(rule.Validate(null, list, null, null));

                list.Add(1);
                Assert.IsNotNull(rule.Validate(null, list, null, null));

                list.Add(1);
                Assert.IsNull(rule.Validate(null, list, null, null));

                list.Add(1);
                Assert.IsNull(rule.Validate(null, list, null, null));

                list.Add(1);
                Assert.IsNull(rule.Validate(null, list, null, null));

                list.Add(1);
                Assert.IsNotNull(rule.Validate(null, list, null, null));
            }
            [Test]
            public void ValidateNonGenericExcludeDuplicates()
            {
                var rule = new LengthCollectionRule(null, false, expectedMinimum, expectedMaximum, true, null);
                    rule.CheckType(new MockInfoDescriptor(typeof(ArrayList).TypeHandle, "foo"));
                ArrayList list = null;
                Assert.IsNull(rule.Validate(null, list, null, null));

                list = new ArrayList();
                Assert.IsNotNull(rule.Validate(null, list, null, null));

                list.Add(1);
                Assert.IsNotNull(rule.Validate(null, list, null, null));

                list.Add(1);
                Assert.IsNotNull(rule.Validate(null, list, null, null));

                list.Add(1);
                Assert.IsNotNull(rule.Validate(null, list, null, null));

                list.Add(2);
                Assert.IsNull(rule.Validate(null, list, null, null));

                list.Add(3);
                Assert.IsNull(rule.Validate(null, list, null, null));

                list.Add(4);
                Assert.IsNull(rule.Validate(null, list, null, null));

                list.Add(5);
                Assert.IsNotNull(rule.Validate(null, list, null, null));
            }
#endif

            [Test]
            public void ValidateNonICollection()
            {
                var rule = new LengthCollectionRule(null, false, 2, 7, false, null);
                rule.CheckType(new MockInfoDescriptor(typeof(MyCollection).TypeHandle, "foo"));
                Assert.IsNull(rule.Validate(null, new MyCollection(), null, null));
            }



        }




        [TestFixture]
        public class CheckTypes
        {

            [Test]
            public void Simple()
            {
                var rule = new LengthCollectionRule(null, false, expectedMinimum, expectedMaximum, true, null);
                rule.CheckType(new MockInfoDescriptor(typeof (IList<int>).TypeHandle, "foo"));
                rule = new LengthCollectionRule(null, false, expectedMinimum, expectedMaximum, true, null);
						rule.CheckType(new MockInfoDescriptor(typeof (List<int>).TypeHandle, "foo"));
                rule = new LengthCollectionRule(null, false, expectedMinimum, expectedMaximum, true, null);
						rule.CheckType(new MockInfoDescriptor(typeof(ICollection<int>).TypeHandle, "foo"));
                rule = new LengthCollectionRule(null, false, expectedMinimum, expectedMaximum, true, null);
						rule.CheckType(new MockInfoDescriptor(typeof(LinkedList<int>).TypeHandle, "foo"));
                rule = new LengthCollectionRule(null, false, expectedMinimum, expectedMaximum, true, null);
						rule.CheckType(new MockInfoDescriptor(typeof(Stack<int>).TypeHandle, "foo"));
#if (!SILVERLIGHT)
                rule = new LengthCollectionRule(null, false, expectedMinimum, expectedMaximum, true, null);
						rule.CheckType(new MockInfoDescriptor(typeof(ArrayList).TypeHandle, "foo"));
#endif
                rule = new LengthCollectionRule(null, false, expectedMinimum, expectedMaximum, true, null);
                rule.CheckType(new MockInfoDescriptor(typeof(int[]).TypeHandle, "foo"));

            }


            [Test]
            [ExpectedException(typeof(ArgumentException), ExpectedMessage = "Property must be a ICollection<T> or ICollection to be used for the LengthCollectionRule.")]
            public void ExceptionNoCollection()
            {
                var rule = new LengthCollectionRule(null, false, expectedMinimum, expectedMaximum, true, null);
                rule.CheckType(new MockInfoDescriptor(TypePointers.IntTypeHandle, "foo"));
            }
        }


    }
}